/*     */ package com.zimbra.cs.security.kerberos;
/*     */ 
/*     */ import java.io.EOFException;
/*     */ import java.io.File;
/*     */ import java.io.IOException;
/*     */ import java.io.PrintStream;
/*     */ import java.io.RandomAccessFile;
/*     */ import java.io.UnsupportedEncodingException;
/*     */ import java.math.BigInteger;
/*     */ import java.nio.ByteBuffer;
/*     */ import java.nio.ByteOrder;
/*     */ import java.nio.channels.FileChannel;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Collections;
/*     */ import java.util.HashMap;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.Set;
/*     */ import javax.security.auth.kerberos.KerberosKey;
/*     */ import javax.security.auth.kerberos.KerberosPrincipal;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class Krb5Keytab
/*     */ {
/*     */   private final File file;
/*     */   private final Map<KerberosPrincipal, List<KerberosKey>> keyMap;
/*     */   private long lastModified;
/*     */   private int version;
/*     */   private static final int VERSION_1 = 1281;
/*     */   private static final int VERSION_2 = 1282;
/*  54 */   private static Map<File, Krb5Keytab> keytabs = new HashMap();
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static synchronized Krb5Keytab getInstance(String path)
/*     */     throws IOException
/*     */   {
/*  68 */     File file = new File(path).getCanonicalFile();
/*  69 */     Krb5Keytab keytab = (Krb5Keytab)keytabs.get(file);
/*  70 */     if (keytab == null) {
/*  71 */       keytab = new Krb5Keytab(file);
/*  72 */       keytabs.put(file, keytab);
/*     */     }
/*  74 */     return keytab;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static Krb5Keytab getInstance(File file)
/*     */     throws IOException
/*     */   {
/*  87 */     return getInstance(file.getPath());
/*     */   }
/*     */   
/*     */   private Krb5Keytab(File file) throws IOException {
/*  91 */     this.file = file;
/*  92 */     this.keyMap = new HashMap();
/*  93 */     loadKeytab();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized List<KerberosKey> getKeys(KerberosPrincipal kp)
/*     */     throws IOException
/*     */   {
/* 107 */     checkLastModified();
/* 108 */     List<KerberosKey> keys = (List)this.keyMap.get(kp);
/* 109 */     return keys != null ? Collections.unmodifiableList(keys) : null;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public File getFile()
/*     */   {
/* 118 */     return this.file;
/*     */   }
/*     */   
/*     */   private void checkLastModified() throws IOException
/*     */   {
/* 123 */     if (this.file.lastModified() != this.lastModified) loadKeytab();
/*     */   }
/*     */   
/*     */   private void loadKeytab() throws IOException {
/* 127 */     RandomAccessFile raf = new RandomAccessFile(this.file, "r");
/*     */     try {
/* 129 */       this.lastModified = this.file.lastModified();
/* 130 */       this.version = readVersion(raf);
/* 131 */       if ((this.version != 1281) && (this.version != 1282)) {
/* 132 */         throw formatError("Unsupported file format version 0x" + Integer.toHexString(this.version));
/*     */       }
/*     */       
/* 135 */       this.keyMap.clear();
/* 136 */       FileChannel fc = raf.getChannel();
/* 137 */       while (fc.position() < fc.size()) readEntry(fc);
/*     */     } finally {
/* 139 */       raf.close();
/*     */     }
/*     */   }
/*     */   
/*     */   private static int readVersion(RandomAccessFile raf) throws IOException {
/* 144 */     int hi = raf.readUnsignedByte();
/* 145 */     int lo = raf.readUnsignedByte();
/* 146 */     return hi << 8 | lo;
/*     */   }
/*     */   
/*     */   private void readEntry(FileChannel fc) throws IOException {
/* 150 */     int size = readInt(fc);
/* 151 */     if (size < 0)
/*     */     {
/* 153 */       long newPos = fc.position() + -size;
/* 154 */       if (newPos >= fc.size()) {
/* 155 */         throw new EOFException();
/*     */       }
/* 157 */       fc.position(newPos);
/* 158 */       return;
/*     */     }
/* 160 */     ByteBuffer bb = readBytes(fc, size);
/*     */     try {
/* 162 */       KerberosPrincipal kp = getPrincipal(bb);
/* 163 */       KerberosKey key = getKey(bb, kp);
/* 164 */       addKey(kp, key);
/*     */     } catch (ArrayIndexOutOfBoundsException e) {
/* 166 */       throw formatError("Invalid entry size " + size);
/*     */     }
/*     */   }
/*     */   
/*     */   private KerberosPrincipal getPrincipal(ByteBuffer bb) throws IOException {
/* 171 */     int count = bb.getShort() & 0xFFFF;
/* 172 */     if (this.version == 1281) count--;
/* 173 */     if (count < 1) {
/* 174 */       throw formatError("Invalid component count (" + count + ")");
/*     */     }
/* 176 */     String realm = getString(bb);
/* 177 */     StringBuilder sb = new StringBuilder();
/* 178 */     for (int i = 0; i < count - 1; i++) {
/* 179 */       sb.append(getString(bb)).append('/');
/*     */     }
/* 181 */     sb.append(getString(bb)).append('@').append(realm);
/* 182 */     String name = sb.toString();
/* 183 */     int type = this.version == 1281 ? 1 : bb.getInt();
/*     */     
/* 185 */     bb.getInt();
/* 186 */     return new KerberosPrincipal(name, type);
/*     */   }
/*     */   
/*     */   private KerberosKey getKey(ByteBuffer bb, KerberosPrincipal kp) {
/* 190 */     int vno = bb.get() & 0xFF;
/* 191 */     int type = bb.getShort() & 0xFFFF;
/* 192 */     byte[] b = getBytes(bb);
/* 193 */     if (bb.remaining() >= 4) {
/* 194 */       vno = bb.getInt();
/*     */     }
/* 196 */     return new KerberosKey(kp, b, type, vno);
/*     */   }
/*     */   
/*     */   private void addKey(KerberosPrincipal kp, KerberosKey key) {
/* 200 */     List<KerberosKey> keys = (List)this.keyMap.get(kp);
/* 201 */     if (keys == null) {
/* 202 */       keys = new ArrayList();
/* 203 */       this.keyMap.put(kp, keys);
/*     */     }
/* 205 */     keys.add(key);
/*     */   }
/*     */   
/*     */   private String getString(ByteBuffer bb) {
/*     */     try {
/* 210 */       return new String(getBytes(bb), "US-ASCII");
/*     */     } catch (UnsupportedEncodingException e) {
/* 212 */       throw new InternalError("US-ASCII encoding not supported");
/*     */     }
/*     */   }
/*     */   
/*     */   private byte[] getBytes(ByteBuffer bb) {
/* 217 */     int len = bb.getShort() & 0xFFFF;
/* 218 */     byte[] b = new byte[len];
/* 219 */     bb.get(b);
/* 220 */     return b;
/*     */   }
/*     */   
/*     */   private int readInt(FileChannel fc) throws IOException {
/* 224 */     return readBytes(fc, 4).getInt();
/*     */   }
/*     */   
/*     */   private ByteBuffer readBytes(FileChannel fc, int size) throws IOException {
/* 228 */     ByteBuffer bb = ByteBuffer.allocate(size);
/* 229 */     while (bb.hasRemaining()) {
/* 230 */       if (fc.read(bb) == -1) {
/* 231 */         throw new EOFException();
/*     */       }
/*     */     }
/* 234 */     bb.flip();
/* 235 */     if (this.version == 1281) {
/* 236 */       bb.order(ByteOrder.LITTLE_ENDIAN);
/*     */     }
/* 238 */     return bb;
/*     */   }
/*     */   
/*     */   private IOException formatError(String s) {
/* 242 */     return new IOException("Invalid keytab file '" + this.file + "': " + s);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void dump(PrintStream ps)
/*     */   {
/* 251 */     ps.printf("Keytab name: %s\n", new Object[] { this.file });
/* 252 */     ps.printf("Keytab version: 0x%x\n", new Object[] { Integer.valueOf(this.version) });
/* 253 */     ps.printf("KVNO Principal\n", new Object[0]);
/* 254 */     ps.print("---- ");
/* 255 */     for (int i = 0; i < 75; i++) ps.print('-');
/* 256 */     ps.println();
/* 257 */     for (Iterator i$ = this.keyMap.keySet().iterator(); i$.hasNext();) { kp = (KerberosPrincipal)i$.next();
/* 258 */       for (KerberosKey key : (List)this.keyMap.get(kp)) {
/* 259 */         ps.printf("%4d %s (%s) (0x%x)\n", new Object[] { Integer.valueOf(key.getVersionNumber()), kp.getName(), getKeyTypeName(key.getKeyType()), new BigInteger(1, key.getEncoded()) });
/*     */       }
/*     */     }
/*     */     
/*     */     KerberosPrincipal kp;
/*     */   }
/*     */   
/*     */   private static String getKeyTypeName(int keyType)
/*     */   {
/* 268 */     switch (keyType) {
/* 269 */     case 0:  return "No encryption";
/* 270 */     case 1:  return "DES cbc mode with CRC-32";
/* 271 */     case 2:  return "DES cbc mode with RSA-MD4";
/* 272 */     case 3:  return "DES cbc mode with RSA-MD5";
/* 273 */     case 4:  return "DES cbc mode raw";
/* 274 */     case 6:  return "Triple DES cbc mode raw";
/* 275 */     case 8:  return "DES with HMAC/sha1";
/* 276 */     case 16:  return "Triple DES cbc mode with HMAC/sha1";
/* 277 */     case 17:  return "AES-128 CTS mode with 96-bit SHA-1 HMAC";
/* 278 */     case 18:  return "AES-256 CTS mode with 96-bit SHA-1 HMAC";
/* 279 */     case 23:  return "ArcFour with HMAC/md5";
/* 280 */     case 24:  return "Exportable ArcFour with HMAC/md5"; }
/* 281 */     return "Unknown type 0x" + Integer.toHexString(keyType);
/*     */   }
/*     */   
/*     */   public static void main(String... args) throws Exception
/*     */   {
/* 286 */     getInstance(args[0]).dump(System.out);
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/security/kerberos/Krb5Keytab.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */